package com.blue.common.aop;

import com.blue.common.annotation.NotNull;
import com.blue.common.annotation.NotNulls;
import com.blue.common.exception.CustomException;
import org.aspectj.lang.ProceedingJoinPoint;
import org.aspectj.lang.annotation.Around;
import org.aspectj.lang.annotation.Aspect;
import org.aspectj.lang.annotation.Pointcut;
import org.aspectj.lang.reflect.MethodSignature;
import org.springframework.stereotype.Component;

import java.lang.annotation.Annotation;
import java.lang.reflect.Field;
import java.lang.reflect.Method;

/**
 * @author nanjie.chen
 * Created on 2022/3/20
 */
@Component
@Aspect
public class ParamCheckAop {

    @Pointcut("@annotation(com.blue.common.annotation.NotNull) || @annotation(com.blue.common.annotation.NotNulls)")
    public void pointCut() {
    }

    @Around("pointCut()")
    public Object checkParam(ProceedingJoinPoint proceedingJoinPoint) throws Throwable {
        MethodSignature signature = (MethodSignature) proceedingJoinPoint.getSignature();
        //得到拦截的方法
        Method method = signature.getMethod();
        //获取方法参数注解
        Annotation[] annotations = method.getAnnotations();
        for (Annotation annotation : annotations) {
            //存在非空注解判断执行
            if (annotation instanceof NotNulls) {
                NotNull[] value = ((NotNulls) annotation).value();
                for (NotNull notNull : value) {
                    paramCheck(proceedingJoinPoint, notNull);
                }
            } else if (annotation instanceof NotNull notNull) {
                //获取注解中的值
                paramCheck(proceedingJoinPoint, notNull);
            }
        }
        return proceedingJoinPoint.proceed();
    }

    private void paramCheck(ProceedingJoinPoint proceedingJoinPoint, NotNull notNull) throws IllegalAccessException {
        //获取注解中的值
        String filed = notNull.value();
        String message = notNull.message();
        //获取方法参数
        Object[] args = proceedingJoinPoint.getArgs();
        for (Object arg : args) {
            //以下类型不做校验
            if (arg instanceof String || arg instanceof Integer
                    || arg instanceof Double || arg instanceof Long
                    || arg instanceof Float || arg instanceof Boolean) {
                continue;
            }
            Class<?> aClass = arg.getClass();
            Field declaredField;
            try {
                //获取字段对象
                declaredField = aClass.getDeclaredField(filed);
            } catch (NoSuchFieldException ignored) {
                //如不存在该字段直接跳过
                continue;
            }
            declaredField.setAccessible(true);
            //获取字段属性做非空判断
            Object obj = declaredField.get(arg);
            if (obj == null || "".equals(obj)) {
                throw new CustomException(message);
            }
        }
    }
}
